数据结构串的基本操作及KMP算法

41 篇文章 4 订阅
38 篇文章 2 订阅

将串的基本操作C语言实现,实现KMP算法算出NEXT函数和NEXTVAL的值。

SqString.h的基本内容

typedef int Status;
typedef struct
{
    unsigned char data[MAXSTRLEN+1];
    int length;
}SString;

Status StrInput(SString &S);
void StrAssign(SString &s,char cstr[]);
Status StrOutput(SString S);
Status Concat(SString &T, SString S1, SString S2);
Status SubString(SString &Sub, SString S, int pos, int len);
Status GetStrLength(SString S);
Status ClearStr(SString &S);
Status StrIsEmpty(SString S);
Status StrCopy(SString &T, SString S);
Status StrIndex(SString S, SString T, int pos);
bool StrCompare(SString S, SString T);
Status StrInsert(SString &S, int pos, SString T);
Status StrDelete(SString &S, int pos, int len);
Status DestroyStr(SString &S);
void get_next(SString S, int *next);
int KMP(SString S, SString T, int pos);

函数具体实现

① 初始化串(本文给了两种方法)
将所给字符串放入串S中或者从键盘输入字符串

void StrAssign(SString &s,char cstr[])
{
    int i;
    for (i=1;cstr[i-1]!='\0';i++)
        s.data[i]=cstr[i-1];
    s.length=i-1;
}
Status StrInput(SString &S)
{
    printf("请输入要输入的数量:\n");
    int n;
    scanf("%d",&n);
    int i;
    printf("请输入%d个字符:\n");
    getchar();
    for(i=0;i<n;i++)
        scanf("%c",&S.data[i+1]);
        S.length=n;
    return OK;
}

② 字符串的输出

//字符串的输出
Status StrOutput(SString S)
{
    int i;
    for(i=1;i<=S.length;i++)
        printf("%2c ",S.data[i]);
    printf("\n");
    return OK;
}




//  符串的拼接
Status Concat(SString &T, SString S1, SString S2)
{
    int i;
    bool uncut;
    if (S1.length + S2.length <= MAXSTRLEN)
    {
        for (i = 0; i <= S1.length; i++)
            T.data[i] = S1.data[i];
        for (i = S1.length + 1; i <= S1.length + S2.length; i++)
            T.data[i] = S2.data[i - S1.length];
        T.length = S1.length + S2.length;
        uncut = TRUE;
    }
    else if (S1.length<MAXSTRLEN)
    {
        for (i = 0; i <= S1.length; i++)
            T.data[i] = S1.data[i];
        for (i = S1.length + 1; i <= MAXSTRLEN; i++)
            T.data[i] = S2.data[i - S1.length];
        T.length = MAXSTRLEN;
        uncut = FALSE;
    }
    else
    {
        for (i = 0; i <= MAXSTRLEN; i++)
            T.data[i] = S1.data[i];
        uncut = FALSE;
    }
    return uncut;
}

//  返回需要的子字符串
Status SubString(SString &Sub, SString S, int pos, int len)
{
    int i;
    if (pos<1 || pos>S.length || len<0 || len>S.length - pos + 1)
        return ERROR;
    for (i = 1; i <= len; i++)
        Sub.data[i] = S.data[pos + i - 1];
    Sub.length = len;
    return OK;
}

//  询长度
Status GetStrLength(SString S)
{
    return S.length;
}
//  清除串
Status ClearStr(SString &S)
{
    int i;
    for (i = 1; i <= S.length; i++)
        S.data[i] = '\0';
    S.length = 0;
    return OK;
}
//  判断串是否为空
Status StrIsEmpty(SString S)
{
    if (S.length = 0)
        return 1;
    else
        return ERROR;
}
//  将串S复制给T
Status StrCopy(SString &T, SString S)
{
    int i;
    for (i = 0; i <= S.length; i++)
    {
        T.data[i] = S.data[i];
    }
    return OK;
}
//  搞复杂度查询子串
Status StrIndex(SString S, SString T, int pos)
{
    int i=pos+1,j=1;
    while(i<=S.length&&j<=T.length)
    {
        if(S.data[i]==T.data[j])
        {
            ++i;++j;
        }
        else
        {
            i=i-j+2;j=1;
        }
    }
    if(j>T.length)return i-T.length;
    else return FALSE;
}
//判断串是否相等
bool StrCompare(SString S, SString T)
{
    bool cmp=TRUE;;
    if (T.length != S.length)
        cmp=FALSE;
    else
    {
        int i;
        for(i=1;i<=T.length;i++)
        {
            if(T.data[i]!=S.data[i])
            {
                cmp=FALSE;break;
            }
        }
    }
    return cmp;
}
//串的插入
Status StrInsert(SString &S, int pos, SString T)
{
    int i;
    if (S.length + T.length > MAXSTRLEN || pos<=0 || pos>S.length)
        return ERROR;
    for (i = T.length + S.length; i >= S.length; i--)
        S.data[i] = S.data[i - T.length];
    for (i = 1; i <= T.length; i++)
        S.data[pos+i-1] = T.data[i];
    S.length+=T.length;
    return OK;
}



//串的删除
Status StrDelete(SString &S, int pos, int len)
{
    int i;
    if (pos<1 || pos>S.length || len<0 || len>S.length - pos + 1)
        return ERROR;
    for (i = pos; i <= pos+len; i++)
        S.data[i] = S.data[i + 1];
    S.length = S.length - len;
    return OK;
}//销毁串
Status DestroyStr(SString &S)
{
    int i;
    for (i = MAXSTRLEN; i >= 0; i--)
        free(S.data + i);
    return OK;
}

KMP算法部分,包括next函数和修正的nextval函数

void get_next(SString S, int *next)
{
    int i=1,j=0;
    next[1] = 0;
    while (i < S.length)
    {
        if (j == 0 || S.data[i] == S.data[j])
        {
            ++i;
            ++j;
            next[i] = j;
        }
        else{
            j = next[j];
        }
    }
    for(i=1;i<=S.length;i++)
        printf("%2d ",next[i]);
}



void get_nextval(SString T,int *nextval)
{
    int i=1;nextval[1]=0;
    int j=0;
    while(i<T.length)
    {
        if(j==0||T.data[i]==T.data[j])
        {
            ++i;++j;
            if(T.data[i]!=T.data[j])nextval[i]=j;
            else nextval[i]=nextval[j];
        }
        else j=nextval[j];
    }
    for(i=1;i<=T.length;i++)
        printf("%2d ",nextval[i]);
}


int KMP(SString S,SString T,int pos)
{
    int i = pos;
    int j = 1;
    int next[MAXSTRLEN];
    get_next(T, next);
    while (i <= S.length && j <= T.length){
        if (j == 1 || S.data[i] == T.data[j]){
            ++i;
            ++j;
        }
        else{
            j = next[j];
        }
    }
    if (j>T.length)
        return i - T.length;
    else return 0;
}



int KMPval(SString S,SString T,int pos)
{
    int i = pos;
    int j = 1;
    int nextval[MAXSTRLEN];
    get_nextval(T, nextval);
    while (i <= S.length && j <= T.length){
        if (j == 0 || S.data[i] == T.data[j]){
            ++i;
            ++j;
        }
        else{
            j = nextval[j];
        }
    }
    if (j>T.length){
        return i - T.length;
    }
    else return 0;
}

这里写图片描述
主函数部分:

int main(int argc, char* argv[])
{
    int j,pos=0;
    SString S,T;
    printf("----------------------------------------------------------\n");
    StrAssign(S,"ILOVEGOOGLENOW!");
    StrAssign(T,"GOOGLE");
    printf("S为:\n");StrOutput(S);
    printf("串S长度 %d  ",GetStrLength(S));
    printf("\n");
    printf("T为:\n");StrOutput(T);
    printf("串S长度 %d  ",GetStrLength(T));
    printf("\n");
    printf("----------------------------------------------------------\n");
    printf("简单匹配算法:\n");
    printf("t在s中的位置=%d\n",StrIndex(S,T,0));
    printf("----------------------------------------------------------\n");
    printf("   T    ");
    StrOutput(T);
    printf(" next   ");KMP(S,T,0);
    printf("\n");
    printf(" nextval");KMPval(S,T,0);
    printf("\n");
    printf("----------------------------------------------------------\n");
    printf("KMP算法:\nnext的值  ");
    printf("  \nt在s中的位置=%d\n",KMP(S,T,0));
    printf("----------------------------------------------------------\n");
    printf("修正KMP算法:\nnextval的值");
    printf("  \nt在s中的位置=%d\n",KMPval(S,T,0));
    printf("----------------------------------------------------------\n");
    return 0;
}

总结:

  1. 由于数组是unsigned char类型,如果像书上把S[0]存储数组长度不妥,类型不匹配,建议不使用,建议使用改进的结构体SString类型。
  2. 注意每个函数实现时,S.data[0]不作为存储,应该从1开始。
    欢迎关注我的博客:omegaxyz.com
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
KMP算法是一种字符匹配算法,可以在一个主中查找一个模式是否出现。这里提供一个用C语言实现的KMP算法。 首先,需要定义一个函数`get_next`,用于计算模式的next数组。next数组是一个长度为模式长度的整型数组,表示当匹配失败时,模式应该向右移动的位数。 ```c void get_next(char* pattern, int* next) { int i = 0, j = -1; next[0] = -1; while (i < strlen(pattern)) { if (j == -1 || pattern[i] == pattern[j]) { i++; j++; next[i] = j; } else { j = next[j]; } } } ``` 接下来,定义一个函数`kmp`,用于在主中查找模式。函数的参数包括主指针、主长度、模式指针、模式长度和next数组。 ```c int kmp(char* text, int text_len, char* pattern, int pattern_len, int* next) { int i = 0, j = 0; while (i < text_len && j < pattern_len) { if (j == -1 || text[i] == pattern[j]) { i++; j++; } else { j = next[j]; } } if (j == pattern_len) { return i - j; } else { return -1; } } ``` 下面是一个完整的示例代码: ```c #include <stdio.h> #include <string.h> void get_next(char* pattern, int* next) { int i = 0, j = -1; next[0] = -1; while (i < strlen(pattern)) { if (j == -1 || pattern[i] == pattern[j]) { i++; j++; next[i] = j; } else { j = next[j]; } } } int kmp(char* text, int text_len, char* pattern, int pattern_len, int* next) { int i = 0, j = 0; while (i < text_len && j < pattern_len) { if (j == -1 || text[i] == pattern[j]) { i++; j++; } else { j = next[j]; } } if (j == pattern_len) { return i - j; } else { return -1; } } int main() { char text[] = "ABABABABCABAAB"; char pattern[] = "ABABCABAA"; int text_len = strlen(text); int pattern_len = strlen(pattern); int next[pattern_len]; get_next(pattern, next); int pos = kmp(text, text_len, pattern, pattern_len, next); if (pos == -1) { printf("Pattern not found.\n"); } else { printf("Pattern found at position %d.\n", pos); } return 0; } ``` 输出结果为: ``` Pattern found at position 6. ``` 表示在主中找到了模式,并且位置为6。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值